package com.rowline.admin.module.study.generic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * ClassName:GenericsAndCovariance
 * Created by 245167
 * on 2017/11/16  16:53
 * description:
 */
public class GenericsAndCovarianceTest {

    static List<Apple> apples = Arrays.asList(new Apple());
    static List<Fruit> fruit = Arrays.asList(new Fruit());

    static class Reader<T>{
        T readExact(List<T> list){
            return list.get(0);
        }
    }
    static void f1(){
        Reader<Fruit> fruitRead = new Reader<Fruit>();
        Fruit f = fruitRead.readExact(fruit);
        // 报错，不识别
        // Fruit f = fruitRead.readExact(apples);
        System.out.println("f1() ===> List<T> list");
    }


    static class CovariantReader<T> {
        /**
         * 只要是满足Fruit的子类就行(包括Fruit自身)，这样子类和父类之间的关系也就关联上了
         */
        T readCovariant(List<? extends T> list) {
            return list.get(0);
        }
    }
    static void f2(){
        CovariantReader<Fruit> fruitReader = new CovariantReader<Fruit>();
        Fruit f = fruitReader.readCovariant(fruit);
        Fruit a = fruitReader.readCovariant(apples);
        System.out.println("f2() ===> List<? extends T> list");
    }

    static <T> void writeExact(List<T> list, T item) {
        list.add(item);
        System.out.println("f3() add()===> List<T> list");
    }
    static void f3() {
        //writeExact(apples, new Apple());
        writeExact(fruit, new Fruit());
    }

    static <T> void writeWithWildcard(List<? super T> list, T item) {
        list.add(item);
        System.out.println("f4() add()===> List<? super T> list");
    }
    static void f4() {
        writeWithWildcard(apples, new Apple());
        //writeWithWildcard(fruit, new Apple());
    }


    public static void main(String[] args) {
        f1();
        System.out.println("=========================");
        f2();
        System.out.println("=========================");

        List<? extends Fruit> fruitList = new ArrayList<Apple>();
        /**
         * 实现了<? extends T>的集合类只能将它视为Producer向外提供(get)元素，
         * 而不能作为Consumer来对外获取(add)元素
         */
        //fruitList.add(new Apple());
        //f3();
//        System.out.println("=========================");
//        f4();
//        System.out.println("=========================");

        /**
         * 总结出一条规律，”Producer Extends, Consumer Super”：
             “Producer Extends” - 如果你需要一个只读List，用它来produce T，那么使用? extends T。
             “Consumer Super” - 如果你需要一个只写List，用它来consume T，那么使用? super T。
             如果需要同时读取以及写入，那么我们就不能使用通配符了。
         */

        // 假设我们支持泛型数组的创建，由于运行时期类型信息已经被擦除，
        // JVM实际上根本就不知道new ArrayList<String>()和new ArrayList<Integer>()的区别
//        Object[] stringLists = new List<String>[2];  // compiler error, but pretend it's allowed
//        stringLists[0] = new ArrayList<String>();   // OK
        // An ArrayStoreException should be thrown, but the runtime can't detect it.
//        stringLists[1] = new ArrayList<Integer>();

        Class c1 = new ArrayList<String>().getClass();
        Class c2 = new ArrayList<Integer>().getClass();
        System.out.println("c1 = " + c1);
        System.out.println("c2 = " + c2);
        System.out.println(c1 == c2); // true

        /**
         * List<? super Fruit> 表示“具有任何Fruit超类型的列表”，列表的类型至少是一个 Fruit 类型，因此可以安全的向其中添加Fruit 及其子类型。
         * 由于List<? super Fruit>中的类型可能是任何Fruit 的超类型，无法赋值为Fruit的子类型Apple的List<Apple>.
         */
        List<? super Fruit> fruitExtendsList = new ArrayList<Fruit>();
        fruitExtendsList.add(new Apple());



    }

}
